#include "../common.h"
#include <dlfcn.h>

/*
 * Class:     com_googlecode_dni_internal_library_DynamicLibrary
 * Method:    openImpl
 * Signature: (Ljava/lang/String;)J
 */
JNIEXPORT jlong JNICALL Java_com_googlecode_dni_internal_library_DynamicLibrary_openImpl(
    JNIEnv* env,
    jclass clazz,
    jstring name )
{
    char* nameStr = NULL;
    void* handle;
    char* errorStr;

    if ( name != NULL )
    {
        // TODO Slightly naughty: We assume the platform charset is UTF-8
        nameStr = (char*) (*env)->GetStringUTFChars( env, name, NULL );
	    if ( nameStr == NULL )
	    {
    	    return 0;
        }
    }
	
	handle = dlopen( nameStr, RTLD_NOW );
	errorStr = dlerror();

	if ( name != NULL )
    {
	    (*env)->ReleaseStringUTFChars( env, name, nameStr );
	}

	if ( handle == NULL && errorStr != NULL )
	{
	    (*env)->ThrowNew( env, (*env)->FindClass( env, "java/lang/UnsatisfiedLinkError" ), errorStr );
	    return 0;
	}

	return POINTER_TO_JLONG( handle );
}

/*
 * Class:     com_googlecode_dni_internal_library_DynamicLibrary
 * Method:    getSymbolImpl
 * Signature: (JLjava/lang/String;)J
 */
JNIEXPORT jlong JNICALL Java_com_googlecode_dni_internal_library_DynamicLibrary_getSymbolImpl(
    JNIEnv* env,
    jclass clazz,
    jlong handle,
    jstring name )
{
    char* nameStr;
    void* sym;
    char* errorStr;

    nameStr = (char*) (*env)->GetStringUTFChars( env, name, NULL );
	if ( nameStr == NULL )
	{
	    return 0;
	}
	
	sym = dlsym( JLONG_TO_POINTER( handle ), nameStr );
	errorStr = dlerror();

	(*env)->ReleaseStringUTFChars( env, name, nameStr );

	if ( sym == NULL && errorStr != NULL )
	{
	    (*env)->ThrowNew( env, (*env)->FindClass( env, "com/googlecode/dni/internal/library/SymbolNotFoundException" ), errorStr );
	    return 0;
	}

	return POINTER_TO_JLONG( sym );
}

/*
 * Class:     com_googlecode_dni_internal_library_DynamicLibrary
 * Method:    freeImpl
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_com_googlecode_dni_internal_library_DynamicLibrary_freeImpl(
    JNIEnv* env,
    jclass clazz,
    jlong handle )
{
	char* errorStr;
	
	if ( handle == 0 )
	{
    return;
	}

	dlclose( JLONG_TO_POINTER( handle ) );
	errorStr = dlerror();
	
	if ( errorStr != NULL )
	{
	    (*env)->ThrowNew( env, (*env)->FindClass( env, "java/lang/LinkageError" ), errorStr );
	}
	
    return;
}
